/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is ART OWL API.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2009.
 * All Rights Reserved.
 *
 * The ART OWL API were developed by the Artificial Intelligence Research Group
 * (art.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about the ART OWL API can be obtained at 
 * http://art.uniroma2.it/owlart
 *
 */

package it.uniroma2.art.owlart.utilities;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.io.RDFNodeSerializer;
import it.uniroma2.art.owlart.model.ARTBNode;
import it.uniroma2.art.owlart.model.ARTNode;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.RDFModel;
import it.uniroma2.art.owlart.navigation.ARTLiteralIterator;
import it.uniroma2.art.owlart.navigation.ARTStatementIterator;
import it.uniroma2.art.owlart.vocabulary.OWL;
import it.uniroma2.art.owlart.vocabulary.RDF;

/**
 * this is used to show a node in a human friendly way which is most appropriate for its nature (uri, bnode or
 * literal) and role in the dataset
 * 
 * @author Armando Stellato
 * 
 */
public class RDFRenderer {

	protected static Logger logger = LoggerFactory.getLogger(RDFRenderer.class);

	public static String renderRDFNode(RDFModel model, ARTURIResource resource) throws ModelAccessException {
		return model.getQName(resource.getURI());
	}

	// only dataRange is rendered at the moment
	public static String renderRDFNode(RDFModel model, ARTBNode node) throws ModelAccessException {

		if (model instanceof OWLModel) {
			OWLModel owlModel = (OWLModel) model;
			if (owlModel.isDataRange(node)) {
				logger.trace("rendering owl:Datarange for node: " + node);
				ARTLiteralIterator it = owlModel.parseDataRange(node);
				StringBuffer buffy;
				if (!it.streamOpen())
					buffy = new StringBuffer("{ }");
				else {
					buffy = new StringBuffer("{" + renderRDFNode(model, it.getNext()));
					while (it.streamOpen()) {
						buffy.append(", " + renderRDFNode(model, it.getNext()));
					}
					buffy.append("}");
				}
				it.close();
				return buffy.toString();
			}
			// logger.trace("rendering owl:bnode: " + node);
			// return translateToManchester(owlModel, node, NodeFilters.MAINGRAPH);
		}

		// logger.trace("rendering rdf:bnode: " + node);
		// return translateToManchester(model, node, NodeFilters.MAINGRAPH);
		return RDFNodeSerializer.toNT(node);

	}

	/**
	 * rendering for purposes of showing the node content to the user. This maybe
	 * 
	 * @param model
	 * @param node
	 * @return
	 * @throws ModelAccessException
	 */
	public static String renderRDFNode(RDFModel model, ARTNode node) throws ModelAccessException {
		if (node.isURIResource())
			return renderRDFNode(model, node.asURIResource());
		if (node.isBlank())
			return renderRDFNode(model, node.asBNode());
		else
			return node.asLiteral().getLabel(); // Literal
	}

	// TODO, check those identical assignments!
	/**
	 * rendering of a bNode: translate restrictions starting from ARTNode node in Manchester Syntax edited by
	 * Alfonso Turco
	 * 
	 * @param model
	 * @param node
	 * @param graphs
	 */
	public static String translateToManchester(RDFModel model, ARTNode node, ARTResource... graphs)
			throws ModelAccessException {
		boolean inferred = false;

		String equivalent = "";
		// if(!model.isClass(cls, graphs)) return "ERROR:is not a class";

		if (node.isURIResource())
			return model.getQName(node.getNominalValue());
		if (node.isLiteral())
			return node.asLiteral().getLabel();

		ARTResource cls = node.asResource();

		ARTStatementIterator iter;

		iter = model.listStatements(cls, OWL.Res.COMPLEMENTOF, NodeFilters.ANY, inferred, graphs);
		if (iter.hasNext()) {
			String r = translateToManchester(model, iter.getNext().getObject().asResource(), graphs);
			if (r.indexOf(" ") == -1 || r.startsWith("{"))
				return "not " + r;
			else
				return "not (" + r + ")";
		}

		iter = model.listStatements(cls, OWL.Res.INTERSECTIONOF, NodeFilters.ANY, inferred, graphs);
		if (iter.hasNext()) {
			ARTResource obj = iter.next().getObject().asResource();
			ARTStatementIterator first = model.listStatements(obj, RDF.Res.FIRST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource firstRes = first.next().getObject().asResource();
			String r = translateToManchester(model, firstRes, graphs);
			String inter = "";
			if (r.indexOf(" ") == -1 || r.startsWith("{"))
				inter += r;
			else
				inter += "(" + r + ")";

			ARTStatementIterator rest = model.listStatements(obj, RDF.Res.REST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource restRes = rest.next().getObject().asResource();
			if (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI()))
				inter = inter;
			while (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI())) {
				// passo successivo.

				first = model.listStatements(restRes, RDF.Res.FIRST, NodeFilters.ANY, inferred, graphs);
				firstRes = first.next().getObject().asResource();
				r = translateToManchester(model, firstRes, graphs);
				if (r.indexOf(" ") == -1 || r.startsWith("{"))
					inter = inter + " and " + r;
				else
					inter = inter + " and (" + r + ")";
				rest = model.listStatements(restRes, RDF.Res.REST, NodeFilters.ANY, inferred, graphs);
				restRes = rest.next().getObject().asResource();
			}

			return inter;
		}

		iter = model.listStatements(cls, OWL.Res.UNIONOF, NodeFilters.ANY, inferred, graphs);
		if (iter.hasNext()) {
			ARTResource obj = iter.next().getObject().asResource();
			ARTStatementIterator first = model.listStatements(obj, RDF.Res.FIRST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource firstRes = first.next().getObject().asResource();
			String r = translateToManchester(model, firstRes, graphs);
			String union = "";
			if (r.indexOf(" ") == -1 || r.startsWith("{"))
				union += r;
			else
				union += "(" + r + ")";
			ARTStatementIterator rest = model.listStatements(obj, RDF.Res.REST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource restRes = rest.next().getObject().asResource();
			if (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI()))
				union = union;
			while (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI())) {// CRITICO da controllare
				// passo successivo

				first = model.listStatements(restRes, RDF.Res.FIRST, NodeFilters.ANY, inferred, graphs);
				firstRes = first.next().getObject().asResource();

				r = translateToManchester(model, firstRes, graphs);
				if (r.indexOf(" ") == -1 || r.startsWith("{"))
					union = union + " or " + r;
				else
					union = union + " or (" + r + ")";

				rest = model.listStatements(restRes, RDF.Res.REST, NodeFilters.ANY, inferred, graphs);
				restRes = rest.next().getObject().asResource();
			}

			return union;
		}

		iter = model.listStatements(cls, RDF.Res.TYPE, OWL.Res.RESTRICTION, inferred, graphs);
		if (iter.hasNext()) {
			iter = model.listStatements(cls, OWL.Res.ONPROPERTY, NodeFilters.ANY, inferred, graphs);
			ARTURIResource property = iter.next().getObject().asURIResource();
			String prop = model.getQName(property.getNominalValue());

			iter = model.listStatements(cls, OWL.Res.ALLVALUESFROM, NodeFilters.ANY, inferred, graphs);
			if (iter.hasNext()) {
				ARTResource rest = iter.next().getObject().asResource();
				String r = translateToManchester(model, rest, graphs);
				if (r.indexOf(" ") == -1 || r.startsWith("{"))
					return prop + " only " + r;
				else
					return prop + " only (" + r + ")";
			}

			iter = model.listStatements(cls, OWL.Res.SOMEVALUESFROM, NodeFilters.ANY, inferred, graphs);
			if (iter.hasNext()) {
				ARTResource rest = iter.next().getObject().asResource();
				String r = translateToManchester(model, rest, graphs);
				if (r.indexOf(" ") == -1 || r.startsWith("{"))
					return prop + " some " + r;
				else
					return prop + " some (" + r + ")";
			}

			iter = model.listStatements(cls, OWL.Res.HASVALUE, NodeFilters.ANY, inferred, graphs);
			if (iter.hasNext()) {
				ARTNode rest = iter.next().getObject();
				String r = translateToManchester(model, rest, graphs);
				if (r.indexOf(" ") == -1 || r.startsWith("{"))
					return prop + " value " + r;
				else
					return prop + " value (" + r + ")";
			}

			iter = model.listStatements(cls, OWL.Res.MINCARDINALITY, NodeFilters.ANY, inferred, graphs);
			if (iter.hasNext()) {
				ARTNode rest = iter.next().getObject();
				return prop + " min " + translateToManchester(model, rest, graphs);
			}

			iter = model.listStatements(cls, OWL.Res.MAXCARDINALITY, NodeFilters.ANY, inferred, graphs);
			if (iter.hasNext()) {
				ARTNode rest = iter.next().getObject();
				return prop + " max " + translateToManchester(model, rest, graphs);
			}

			iter = model.listStatements(cls, OWL.Res.CARDINALITY, NodeFilters.ANY, inferred, graphs);
			if (iter.hasNext()) {
				ARTNode rest = iter.next().getObject();
				return prop + " exactly " + translateToManchester(model, rest, graphs);
			}
		}

		iter = model.listStatements(cls, RDF.Res.FIRST, NodeFilters.ANY, inferred, graphs);
		if (iter.hasNext()) {
			ARTResource firstRes = iter.next().getObject().asResource();
			String inter = translateToManchester(model, firstRes, graphs);
			ARTStatementIterator rest = model.listStatements(cls, RDF.Res.REST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource restRes = rest.next().getObject().asResource();
			if (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI()))
				inter = inter;
			while (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI())) {
				// passo successivo.

				ARTStatementIterator first = model.listStatements(restRes, RDF.Res.FIRST, NodeFilters.ANY,
						inferred, graphs);
				firstRes = first.next().getObject().asResource();
				inter = inter + ", " + translateToManchester(model, firstRes, graphs);

				rest = model.listStatements(restRes, RDF.Res.REST, NodeFilters.ANY, inferred, graphs);
				restRes = rest.next().getObject().asResource();
			}

			return inter;
		}

		iter = model.listStatements(cls, OWL.Res.ONEOF, NodeFilters.ANY, inferred, graphs);
		if (iter.hasNext()) {
			ARTResource obj = iter.next().getObject().asResource();
			ARTStatementIterator first = model.listStatements(obj, RDF.Res.FIRST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource firstRes = first.next().getObject().asResource();
			String inter = "{" + translateToManchester(model, firstRes, graphs);
			ARTStatementIterator rest = model.listStatements(obj, RDF.Res.REST, NodeFilters.ANY, inferred,
					graphs);
			ARTResource restRes = rest.next().getObject().asResource();
			if (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI()))
				inter = inter;
			while (!restRes.getNominalValue().equals(RDF.Res.NIL.getURI())) {
				// passo successivo.

				first = model.listStatements(restRes, RDF.Res.FIRST, NodeFilters.ANY, inferred, graphs);
				firstRes = first.next().getObject().asResource();
				inter = inter + "," + translateToManchester(model, firstRes, graphs);

				rest = model.listStatements(restRes, RDF.Res.REST, NodeFilters.ANY, inferred, graphs);
				restRes = rest.next().getObject().asResource();
			}

			return inter + "}";
		}

		return equivalent;
	}

}
